#include <WiFi.h>
#include <HTTPClient.h>
#include <driver/i2s.h>

#include <ArduinoJson.h>
#include <AudioFileSourceHTTPStream.h>
#include <AudioGeneratorMP3.h>
#include <AudioOutputI2S.h>
#include "AudioFileSourceBuffer.h"
#include "AudioFileSourceICYStream.h"

// WiFi 配置
const char* ssid = "xxx";
const char* password = "xxx";
AudioFileSourceICYStream *file;
AudioFileSourceBuffer *buff;
AudioOutputI2S *out = nullptr;
AudioGeneratorMP3 *mp3 = nullptr;
// I2S引脚定义
#define I2S_BCLK 5
#define I2S_LRC 6
#define I2S_DOUT 17

#define I2S_NUM         I2S_NUM_0
#define I2S_SAMPLE_RATE 16000
#define I2S_BITS_PER_SAMPLE I2S_BITS_PER_SAMPLE_16BIT

#define PCM_SAMPLE_SIZE 2 // 16bit

// 串口输入
String getInputText() {
    String input = "";
    while (input.length() == 0) {
        if (Serial.available()) {
            input = Serial.readStringUntil('\n');
            input.trim();
        }
        delay(10);
    }
    return input;
}
String urlEncode(const String &str) {
    String encoded = "";
    char c;
    char code0;
    char code1;
    for (int i = 0; i < str.length(); i++) {
        c = str.charAt(i);
        if (isalnum(c)) {
            encoded += c;
        } else {
            code1 = (c & 0xf) + '0';
            if ((c & 0xf) > 9) code1 = (c & 0xf) - 10 + 'A';
            c = (c >> 4) & 0xf;
            code0 = c + '0';
            if (c > 9) code0 = c - 10 + 'A';
            encoded += '%';
            encoded += code0;
            encoded += code1;
        }
    }
    return encoded;
}
void StatusCallback(void *cbData, int code, const char *string) {
  Serial.printf("STATUS: %d = %s\n", code, string);
}
void playMp3Stream(const String& mp3Url) {
    if (mp3) { mp3->stop(); delete mp3; mp3 = nullptr; }
    if (buff) { delete buff; buff = nullptr; }
    if (file) { delete file; file = nullptr; }
    if (out) { delete out; out = nullptr; }
    //file = new AudioFileSourceHTTPStream(mp3Url.c_str());
    file = new AudioFileSourceICYStream(mp3Url.c_str());
    buff = new AudioFileSourceBuffer(file, 8*1024);
    if (!buff) {
      Serial.println("SPIRAMBuffer 分配失败！");
    }
    out = new AudioOutputI2S();
    out->SetPinout(I2S_BCLK, I2S_LRC, I2S_DOUT);

    mp3 = new AudioGeneratorMP3();
    //mp3->RegisterStatusCB(StatusCallback, nullptr);
    mp3->begin(buff, out);

    Serial.println("开始解码并播放MP3...");
    unsigned long startTime = millis();
    unsigned long maxDuration = 5 * 60 * 1000; // 5分钟

    while (mp3->isRunning() && (millis() - startTime < maxDuration)) {
        if (!mp3->loop()) {
            break;
        }
        delay(1);
    }
    Serial.println("播放完成！");
    mp3->stop();
    delete mp3; mp3 = nullptr;
    delete buff; buff = nullptr;
    delete file; file = nullptr;
    delete out; out = nullptr;
}
void downloadAndPlayMusic(const String& songName) {
    String searchUrl = "http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s=" + urlEncode(songName) + "&type=1&offset=0&total=true&limit=1";
    HTTPClient http;
    http.begin(searchUrl);
    int httpCode = http.GET();
    if (httpCode == HTTP_CODE_OK) {
        String payload = http.getString();
        http.end();

        StaticJsonDocument<4096> doc;
        DeserializationError error = deserializeJson(doc, payload);
        if (error) {
            Serial.print("JSON解析失败: ");
            Serial.println(error.c_str());
            return;
        }
        int songCount = doc["result"]["songCount"];
        if (songCount == 0) {
            Serial.println("未找到歌曲");
            return;
        }
        String songId = String((long)doc["result"]["songs"][0]["id"]);
        String realName = String((const char*)doc["result"]["songs"][0]["name"]);
        Serial.println("找到歌曲: " + realName + "，id: " + songId);

        String musicUrl = "http://music.163.com/song/media/outer/url?id=" + songId + ".mp3";
        HTTPClient musicHttp;
        musicHttp.begin(musicUrl);
        int musicCode = musicHttp.GET();
        // 处理 302 跳转
        if (musicCode == HTTP_CODE_MOVED_PERMANENTLY || musicCode == HTTP_CODE_FOUND) { // 301 或 302
            String realUrl = musicHttp.getLocation();
            musicHttp.end();
            Serial.println("跳转到真实音乐地址: " + realUrl);
            playMp3Stream(realUrl);
            
        }
    }
}
void setup() {
    Serial.begin(115200);
    WiFi.begin(ssid, password);
    Serial.print("WiFi连接中...");
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("连接成功！");
}
void loop() {
    Serial.println("请输入要播放的歌曲名：");
    String songName = getInputText();
    downloadAndPlayMusic(songName);
}
